package rursu.dal.loaders;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import rursu.business.ProgressListener;
import rursu.business.Settings;
import rursu.business.pojo.Movie;
import rursu.business.pojo.MovieImage;
import rursu.business.pojo.MoviesList;
import rursu.dal.managers.DataBaseManager;
import rursu.dal.managers.interfaces.IMovieDAL;
import rursu.dal.managers.interfaces.IMovieDetailsDAL;
import rursu.dal.managers.interfaces.IMovieImageDAL;
import rursu.dal.managers.interfaces.IMoviesListDAL;
import rursu.dal.managers.interfaces.IMoviesListPairDAL;
import rursu.parser.MoviesListParser;
import rursu.parser.MoviesListSAXParser;
import rursu.providers.MoviesListCallback;
import android.os.AsyncTask;

public class MoviesLoaderTask extends AsyncTask<Void, Void, List<Movie>> {	 

	private DataBaseManager dataBaseManager;
	private IMovieDAL movieDALManager;
	private IMoviesListDAL moviesListDALManager;
	private IMoviesListPairDAL moviesListPairDALManager;
	private IMovieImageDAL movieImageDALManager;
	private IMovieDetailsDAL movieDetailsDAL;
	private MoviesListCallback callback;
	private ProgressListener progressListener;
	private Settings settings;
	private String url;
	private String order;
	
	private final int LIST_VALID_PERIOD = 3*1000*60*60*24; // milliseconds
	
	public MoviesLoaderTask(MoviesListCallback callback) {
		this.callback = callback;
	}
	
	public ProgressListener getProgressListener() {
		return progressListener;
	}

	public void setProgressListener(ProgressListener progressListener) {
		this.progressListener = progressListener;
	}

	@Override
	protected void onPreExecute() {
		super.onPreExecute();
		
		if ( progressListener != null ) {
			progressListener.progressContinue();
		}
	}
	
	@Override
	protected void onCancelled() {
		if (progressListener != null) {
			progressListener.progressFinished();
		}
	}
	
	@Override
	protected List<Movie> doInBackground(Void... links) {
		
		List<Movie> recentMovies = null;
		boolean verificationIsNeeded = false;
		
		movieDALManager = dataBaseManager.getMovieDALManager();
		moviesListDALManager = dataBaseManager.getMoviesListDALManager();
		moviesListPairDALManager = dataBaseManager.getMoviesListPairDALManager();
		movieImageDALManager = dataBaseManager.getMovieImageDALManager();
		movieDetailsDAL = dataBaseManager.getMovieDetailsDALManager();
		
		MoviesList movieListHolder = moviesListDALManager.get(order);
		int oldListId = -1;
		
		if ( movieListHolder != null ) {
			
			oldListId = movieListHolder.getId();
//			return movieDALManager.getMoviesByListId(movieListHolder.getId());
			
			verificationIsNeeded = true;
			
			long currentTime = (new Date()).getTime();
			long recordAge = currentTime - movieListHolder.getDateOfRecord().getTime();		
			
			if ( recordAge < LIST_VALID_PERIOD && !(settings.isChanged()) ) { 
				return movieDALManager.getMoviesByListId(movieListHolder.getId());
			} else {				
				moviesListDALManager.delete(movieListHolder.getId());
			}
		}
			
		// load new movies from network
		recentMovies = downloadMovies();
		
		List<Movie> moviesToUpdate = new ArrayList<Movie>();
		if ( verificationIsNeeded == true ) {
			List<Movie> oldMovies = movieDALManager.getMoviesByListId(movieListHolder.getId());
			
			// delete from list of recent movies those, that already are in DB
			for (Movie newMovie : recentMovies) {
				for (Movie oldMovie : oldMovies) {
					
					if (newMovie.equals(oldMovie)) {
						moviesToUpdate.add(newMovie);
					}
				}
			}
			
			// deleting old movies
			for (Movie oldMovie : recentMovies) {
				
				boolean isFound = false;
				
				for (Movie newMovie : recentMovies) {
					if (oldMovie.equals(newMovie)) {
						isFound = true;
						break;
					}
				}
				
				if (isFound == false) {
					movieDALManager.delete(oldMovie.getId());
					movieDetailsDAL.delete(oldMovie.getId());
					movieImageDALManager.deleteByMovieId(oldMovie.getId());
				}
			}
			
			recentMovies.removeAll(moviesToUpdate);
		}
		
		// save movies in DB
		movieListHolder = new MoviesList();
		movieListHolder.setDateOfRecord(new Date());
		movieListHolder.setOrderBy(order);
		moviesListDALManager.insert(movieListHolder);
		movieListHolder = moviesListDALManager.get(order);
		
		int listId = movieListHolder.getId();
		
		// updating movies that exist
		moviesListPairDALManager.updateListId(oldListId, listId);
		for (Movie movie : moviesToUpdate) {
			movieDALManager.update(movie);
		}
		
		for (Movie movie : recentMovies ) {
			moviesListPairDALManager.insert(movie.getId(), listId);
			
			movieDALManager.insert(movie);
			
			for (MovieImage image : movie.getImages()) {
				
				if (image.getSize().equals("thumb") && image.getType().equals("poster")) {
					
					movieImageDALManager.insert(image, movie.getId(), null);
					
				}
			}
		}
		
		recentMovies.addAll(moviesToUpdate);
		
		return recentMovies;
	}

	@Override
	protected void onPostExecute(List<Movie> result) {
		callback.onDownloaded(result);
		
		
		if (progressListener != null) {
			progressListener.progressFinished();
		}
	}
	
	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public void setOrder(String movieListOrderBy) {		
		order = movieListOrderBy;
	}

	public DataBaseManager getDataBaseManager() {
		return dataBaseManager;
	}

	public void setDataBaseManager(DataBaseManager dataBaseManager) {
		this.dataBaseManager = dataBaseManager;
	}
	
	private List<Movie> downloadMovies() {
		MoviesListParser parser = new MoviesListSAXParser();	
		URL url;
		InputStream inputStream = null;
			
		try {
			url = new URL( this.url );
			inputStream = url.openStream();
			
		} catch (MalformedURLException e) {
				
			e.printStackTrace();
		} catch (IOException e) {
				
			e.printStackTrace();
		}
			
		return parser.parse( inputStream );
	}

	public Settings getSettings() {
		return settings;
	}

	public void setSettings(Settings settings) {
		this.settings = settings;
	}	
	
}
